﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Red.GameData
{
    // represents access model to the flattened object's data
    public class EditorObjectView
    {
        /// <summary>
        /// The global reflection data, this is also retrievable via the RawData but it's also exposed here so it looks less like a hack when you access it :)
        /// </summary>
        public Raw.ReflectionData RootReflection { get; private set; }

        /// <summary>
        /// The global object data collection, this is also retrievable via the RawData but it's also exposed here so it looks less like a hack when you access it :)
        /// </summary>
        public Raw.DataCollection RootDataCollection { get; private set; }

        /// <summary>
        /// The object being edited by this view
        /// </summary>
        public Raw.DataObject RawData { get; private set; }
        
        /// <summary>
        ///  Retrieve object stack, ordered from the most base object to the most derived one (us)
        /// </summary>
        public Raw.DataObject[] RawDataStack { get { return RawData.ObjectStack; } }

        /// <summary>
        /// The resolved reflection class of the object being edited
        /// </summary>
        public Raw.ReflectionClass ReflectionClass { get; private set; }

        /// <summary>
        /// Captured properties for this object
        /// There are two types of properties - single value and arrays
        /// </summary>
        public List<EditorPropertyView> Properties { get; private set; }

        // create editable view of the data object
        public static EditorObjectView CreateView(EditorContext context, Raw.DataObject obj)
        {
            // create object view
            EditorObjectView ret = new EditorObjectView();
            ret.RootReflection = context.Reflection;
            ret.RootDataCollection = context.Data;
            ret.Properties = new List<EditorPropertyView>();
            ret.RawData = obj;

            // resolve object class
            ret.ReflectionClass = Raw.Utils.GetObjectClass( context.Reflection, obj );

            // create property wrappers
            if (ret.ReflectionClass != null)
            {
                foreach (var prop in ret.ReflectionClass.AllProperties)
                {
                    var editProp = new EditorPropertyView(ret, prop);
                    ret.Properties.Add(editProp);
                }
            }

            return ret;
        }

        /// <summary>
        /// Get the actual name of the object, not that this ONLY returns something for a named object (i.e. object that class contains the defined Key).
        /// So for any other cases this will return an empty string. If you want to use this for UI consider using DisplayName as it's safer.
        /// </summary>
        public string Name
        {
            get
            {
                string keyName = ReflectionClass.KeyName;
                if (keyName != "")
                {
                    var prop = RawData.GetPropertyNoCreate(keyName);
                    if (prop != null)
                    {
                        var last = prop.Values.Last();
                        if (last != null)
                        {
                            return String.Format("{0}: '{1}'", ReflectionClass.Name, last.Value);
                        }
                    }
                }

                // no name defined
                return "";
            }
        }

        /// <summary>
        /// </summary>
        public string DisplayName
        {
            get
            {
                // use the proper name if possible
                string name = Name;
                if (name != "")
                    return name;

                // format a safe name
                return String.Format("{0}: '{1}'", ReflectionClass.Name, Raw.Utils.FormatGuid(RawData.ID));
            }
        }

        
    }
   
};

